Load packages
library(tidyverse)
library(gridExtra)
library(cowplot)
library(viridis)
library(ggridges)
library(ggstance)
library(treeio)
library(ggtree)
library(tidytree)
Load and combine data
studies <- read_csv("../data/studies_gsheet.csv")
species <- read_csv("../data/species_gsheet.csv")
fulltree <- read.nexus("../data/consensusTree_10kTrees_298Primates_V3.nex")
refs <- read_csv("../data/ref_nodes.csv")
data <- studies %>%
left_join(species, by = c("species" = "species_file")) %>%
rename(label = species_tree, label2 = updated_nomenclature, num = n) %>%
mutate(label2 = ifelse(is.na(label2), label, label2)) %>%
select(label, label2, studyID, species, site, num)
data2 <- data %>%
group_by(label, label2, species) %>%
summarise(Nsites = n_distinct(site), Nstudies = n_distinct(studyID)) %>%
mutate(div_score = Nsites/Nstudies)
# turn tree into tidy dataframe
tree2 <- fulltree %>%
drop.tip(c("Pan_troglodytes_schweinfurthii", "Pan_troglodytes_troglodytes",
"Pan_troglodytes_vellerosus", "Pongo_pygmaeus", "Cercopithecus_cephus_cephus",
"Cercopithecus_erythrogaster_erythrogaster", "Eulemur_fulvus_mayottensis",
"Hapalemur_griseus_griseus", "Microcebus_lokobensis", "Lepilemur_mitsinjoensis")) %>%
as_tibble
inner_nodes <- c(289:298, 307:308, 313:319, 321:325, 327, 329:346, 349:351, 355:357, 359, 375:383, 388, 392:395, 397:403, 405:416, 423:426, 428:432, 438:442, 446:448, 450:454, 457:464, 466:471, 473:477, 481:492, 504, 522:523, 527:529, 532:536, 542:544, 550:552, 555, 557)
tree3 <- tree2 %>%
mutate(label = fct_recode(label,
"Pongo_spp" = "Pongo_abelii",
"Pan_troglodytes" = "Pan_troglodytes_verus")) %>%
left_join(data2) %>%
left_join(species, by = c("label" = "species_tree")) %>%
select(-label, -label2, -species_file) %>%
rename(label = updated_nomenclature) %>%
mutate(
hasN = ifelse(is.na(Nstudies), .1, .5), # used to size branches + color the tip labels
hasN2 = ifelse(is.na(Nstudies) & !(node %in% inner_nodes), 0, .5), # used to color branches
label = str_replace_all(label, "_", " "),
label = ifelse(is.na(label) & species == "orangutan", "Pongo spp",
ifelse(is.na(label) & species == "chimpanzee", "Pan troglodytes", label))) %>%
left_join(refs) %>%
groupClade(refs$node[-1]) %>%
mutate(group = fct_recode(group, "2" = "1"))
Joining, by = "label"
Column `label` joining factor and character vector, coercing into character vectorJoining, by = "node"
# turn back into tree
tree4 <- as.treedata(tree3)
Circular tree of the 10ktree primates
cols <- viridis(4, end = .9)
p <- ggtree(tree4, aes(alpha = hasN2), layout = "circular") + # size = hasN,
# highlight clades with background colors
geom_hilight(node = 478, fill = cols[1], alpha = .3) +
geom_hilight(node = 481, fill = cols[1], alpha = .3) +
geom_hilight(node = 414, fill = cols[2], alpha = .3) +
geom_hilight(node = 293, fill = cols[3], alpha = .3) +
geom_hilight(node = 397, fill = cols[4], alpha = .3) +
# plot tree again to be on top of the highlights
geom_tree() +
# root
geom_rootpoint(size = 1) +
# tips
geom_tippoint(aes(size = Nstudies), alpha = .7) +
geom_tiplab2(aes(alpha = hasN), offset = 3, size = 3) +
# tweak scales
scale_alpha_continuous(range = c(.2, 1)) +
scale_size_area(max_size = 15) +
# widen plotting area
xlim(NA, 100)
p <- rotate(p, 292)
pcol <- ggplot(tibble(cols = cols, x = 1:4), aes(x, y = 1, col = cols)) +
geom_point(size = 6, alpha = .3) +
scale_color_identity("Clade", guide = "legend", breaks = cols[4:1],
labels = c("Hominoidea", "Cercopithecoidea", "Platyrrhini",
"Tarsiiformes & Strepsirrhini")) +
theme_cowplot()
l1 <- get_legend(pcol)
psize <- ggplot(data2, aes(size = Nstudies, x = 1, y = 1)) +
geom_point(alpha = .7) +
scale_size_area("Number of Studies", max_size = 15) +
theme_cowplot()
l2 <- get_legend(psize)
px <- plot_grid(p, plot_grid(NA, l1, l2, NA, ncol = 1, rel_heights = c(.3, .15, .15, .3)), NA,
nrow = 1, rel_widths = c(1, .2, .1))
Cannot convert object of class logical into a grob.Cannot convert object of class logical into a grob.Removed 219 rows containing missing values (geom_point_g_gtree).Cannot convert object of class logical into a grob.
px

ggsave("../graphs/phylo_full.pdf", px, width = 7, height = 5.5, scale = 2)
ggsave("../graphs/phylo_full.png", width = 7, height = 5.5, scale = 2)
ggsave("../graphs/phylo_full.tiff", width = 7, height = 5.5, scale = 2, type = "cairo",
compression = "lzw")
# to figure out node numbers
n1 <- p + geom_text(aes(label = node, x = branch), size = 2, col = "blue", vjust = -.5)
ggsave("../graphs/full_tree_nodes_circular.pdf", n1, width = 8, height = 8, scale = 2)
n2 <- ggtree(tree4, aes(size = hasN, alpha = hasN2)) +
# highlight clades with background colors
geom_hilight(node = 478, fill = cols[1], alpha = .3) +
geom_hilight(node = 481, fill = cols[1], alpha = .3) +
geom_hilight(node = 414, fill = cols[2], alpha = .3) +
geom_hilight(node = 293, fill = cols[3], alpha = .3) +
geom_hilight(node = 397, fill = cols[4], alpha = .3) +
# plot tree again to be on top of the highlights
geom_tree() +
# root
geom_rootedge(rootedge = 2) +
geom_rootpoint(size = 1) +
# node labels
geom_text(aes(label = node, x = branch), size = 2, col = "blue", vjust = -.5) +
# tips
geom_tippoint(aes(size = Nstudies), alpha = .7) +
geom_tiplab(aes(alpha = hasN), offset = 1.8, size = 3) +
# tweak scales
scale_alpha_continuous(range = c(.2, 1)) +
scale_size_continuous(range = c(.5, 15)) +
# widen plotting area
expand_limits(x = 90) +
theme_tree2()
ggsave("../graphs/full_tree_nodes.pdf", n2, width = 8, height = 20, scale = 2)
Sample size in detail
# subset tree to just those species who have sample sizes reported, i.e. those who were tested
to_drop <- tree3 %>% filter(is.na(Nstudies)) %>% pull(label)
tree5 <- drop.tip(tree4, to_drop)
d3 <- data %>%
mutate(label = str_replace_all(label2, "_", " ")) %>%
group_by(label, species, studyID) %>%
summarise(num = sum(num))
d3 %>% arrange(desc(num))
# filter super large samples out for visualization? note in caption
# species with more than X sites can get a density
d3a <- d3 %>% group_by(species) %>% filter(n_distinct(studyID) >= 4, num <= 200)
d3b <- d3 %>% # setdiff(d3, d3a) %>% ## <- to NOT show points for densities
group_by(species) %>%
# create variable num2 is NA if there's only one data point for a species
# --> those species will only get the vertical crossbar
mutate(flag = n_distinct(studyID) == 1) %>%
ungroup %>%
mutate(num2 = ifelse(flag, NA, num)) %>%
filter(num <= 200)
# for vertical crossbar = median
d4 <- d3 %>%
group_by(label, species) %>%
summarise(Mdn = median(num, na.rm = T)) # totalN = sum(num), sitesN = n_distinct(site)
# for vertical line in ridge plot (grand median)
# + hacky way to make horizontal grid lines for right panel only
v <- tibble(reference = c(NA, median(d3$num, na.rm = T)), .panel = c("Tree", "xSample size"))
h <- tibble(reference = c(NA, 1:Ntip(tree5)), .panel = c("Tree", rep("xSample size", Ntip(tree5))))
# for axis labels
ax <- tibble(lab = c("Distance (Millions of years)", "Sample size"),
x = c(60, 100), y = -4, .panel = c("Tree", "xSample size"))
# Nsites/studies labels
Nlab <- tibble(lab = c("# Sites", "# Studies"), x = c(125, 136), y = Ntip(tree5) + 1,
.panel = "Tree")
# LEFT FACET
q <- ggtree(tree5, aes(col = group)) +
# root
geom_rootedge(rootedge = 5) +
# tip labels
geom_tippoint(aes(size = Nstudies), shape = 21, fill = "white") +
geom_tippoint(aes(size = Nsites), stroke = 0, alpha = .8) +
# geom_tiplab(aes(label = str_c(label, " (", Nsites, "/", Nstudies, ")")), offset = 4, size = 3) +
geom_tiplab(offset = 4, size = 3) +
geom_text(aes(label = Nsites), x = 135, hjust = 1, size = 3) +
geom_text(aes(label = Nstudies), x = 142, hjust = 1, size = 3) +
# tweak scales
scale_color_manual(values = c("grey30", cols)) +
scale_fill_manual(values = cols) +
scale_size_area(max_size = 8) +
# display timescale at the bottom
theme_tree2() +
xlim_tree(142) +
xlim_expand(c(0, 175), "xSample size") +
# add axis + Nstudies/sites labels
geom_text(data = ax, aes(label = lab), col = "black") +
geom_text(data = Nlab, aes(label = lab), col = "black", size = 2.5) +
scale_x_continuous(expand = expand_scale(mult = c(0, .01))) +
scale_y_continuous(limits = c(2, Ntip(tree5)-1), oob = function(x, ...) x) +
coord_cartesian(clip = "off") +
# add reference lines (these will show up on right panel of facet_plot only)
geom_hline(data = h, aes(yintercept = reference), lwd = .2, col = "grey", alpha = .5) +
geom_vline(data = v, aes(xintercept = reference), lwd = 1.5, col = "grey", alpha = .3) +
# remove facet strips, expand bottom margin (to make space for x axis labels)
theme(strip.text = element_blank(), strip.background = element_blank(),
plot.margin = unit(c(1, 1, 2, 1.5), "cm"), panel.spacing = unit(1, "cm"))
q <- rotate(q, 72)
# right-side viz depends on the number of sites per species:
# 1 site = vertical crossbar only
# 2+ sites = points + crossbar at median
# X+ sites = densities (currently, X = 4 just to illustrate)
# dirty hack: x in front of "Sample size" is to have that panel sort to the right (alphabetically) until I figure out why it doesn't just go by order. This cropped up as an issue when I added the dummy point for the x-axis expansion...
# ADD RIGHT FACET
qx <- q %>%
# densities for species with enough sites
facet_plot("xSample size", d3a, geom_density_ridges,
aes(x = num, group = label, fill = group, height = ..density..),
alpha = .5, lwd = .3, scale = .3) %>%
# vertical crossbar for Mdn
facet_plot("xSample size", d4, geom_crossbarh, aes(x = Mdn, xmin = Mdn, xmax = Mdn, group = label,
col = group), alpha = .5, width = .6, fatten = 1.5) %>%
# vertical mark for individual sites
facet_plot("xSample size", d3b, geom_jitter, aes(x = num2, group = label), shape = "|", size = 2.5,
width = .5, height = 0, alpha = .5)
# add legends
psize <-
ggplot(data2, aes(x = 1, y = 1)) +
geom_point(aes(size = Nstudies), col = NA) +
geom_point(aes(size = Nsites), stroke = 0, alpha = .8) +
scale_size_area("Number of Sites", max_size = 8, breaks = c(1, 5, 10, 25, 50)) +
theme_cowplot()
psize2 <-
ggplot(data2, aes(x = 1, y = 1)) +
geom_point(aes(size = Nstudies), shape = 21, fill = "white") +
scale_size_area("\nNumber of Studies", max_size = 8, breaks = c(1, 5, 10, 25, 50, 100)) +
theme_cowplot()
l2 <- get_legend(psize)
Removed 69 rows containing missing values (geom_point).
l3 <- get_legend(psize2)
qx2 <- plot_grid(qx, plot_grid(NA, l1, l2, l3, NA, ncol = 1, rel_heights = c(.3, .1, .1, .1, .3)), NA,
nrow = 1, rel_widths = c(1, .2, .1))
Cannot convert object of class logical into a grob.Cannot convert object of class logical into a grob.Picking joint bandwidth of NaN
no non-missing arguments to min; returning Infno non-missing arguments to max; returning -InfPicking joint bandwidth of 4.06
no non-missing arguments to max; returning -InfRemoved 67 rows containing missing values (geom_text).Removed 67 rows containing missing values (geom_text).Removed 1 rows containing missing values (geom_hline).Removed 1 rows containing missing values (geom_vline).Removed 1 rows containing missing values (geom_crossbarh).Removed 32 rows containing missing values (geom_point).Cannot convert object of class logical into a grob.
qx2

ggsave("../graphs/phylo_ridge_site.pdf", width = 8, height = 8, scale = 2)
ggsave("../graphs/phylo_ridge_site.png", width = 8, height = 8, scale = 2)
ggsave("../graphs/phylo_ridge_site.tiff", width = 8, height = 8, scale = 2, type = "cairo",
compression = "lzw")
Diversity score
# subset tree to just those species who have sample sizes reported, i.e. those who were tested
to_drop <- tree3 %>% filter(is.na(Nstudies) | Nstudies < 2) %>% pull(label)
tree6 <- drop.tip(tree4, to_drop)
ggtree(tree6, aes(col = group)) +
# root
geom_rootedge(rootedge = 5) +
# tip labels
geom_tippoint(aes(size = Nstudies), shape = 21, fill = "white") +
geom_tippoint(aes(size = Nsites), stroke = 0, alpha = .8) +
geom_tiplab(offset = 4, size = 3) +
geom_text(aes(label = Nsites), x = 113, hjust = 1, size = 3) +
geom_text(aes(label = Nstudies), x = 120, hjust = 1, size = 3) +
# tweak scales
scale_color_manual(values = c("grey30", cols)) +
scale_fill_manual(values = cols) +
scale_size_area(max_size = 8) +
# display timescale at the bottom
theme_tree2() +
xlim_tree(120) +
xlab("Distance (Millions of years)")
# ggsave("../graphs/phylo_div_score.pdf", width = 4, height = 4.5, scale = 2)
Session info
sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.5
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] tidytree_0.2.8 ggtree_1.16.6 treeio_1.8.2 ggstance_0.3.3 ggridges_0.5.1
[6] viridis_0.5.1 viridisLite_0.3.0 cowplot_1.0.0 gridExtra_2.3 forcats_0.4.0
[11] stringr_1.4.0 dplyr_0.8.3 purrr_0.3.2 readr_1.3.1 tidyr_1.0.0
[16] tibble_2.1.3 ggplot2_3.2.1 tidyverse_1.2.1
loaded via a namespace (and not attached):
[1] tidyselect_0.2.5 xfun_0.10 reshape2_1.4.3 haven_2.1.1 lattice_0.20-38
[6] colorspace_1.4-1 vctrs_0.2.0 generics_0.0.2 rlang_0.4.0 pillar_1.4.2
[11] glue_1.3.1 withr_2.1.2 modelr_0.1.5 readxl_1.3.1 rvcheck_0.1.5
[16] lifecycle_0.1.0 plyr_1.8.4 munsell_0.5.0 gtable_0.3.0 cellranger_1.1.0
[21] rvest_0.3.4 labeling_0.3 knitr_1.25 parallel_3.6.1 broom_0.5.2
[26] Rcpp_1.0.2 BiocManager_1.30.7 scales_1.0.0 backports_1.1.5 jsonlite_1.6
[31] digest_0.6.21 hms_0.5.1 stringi_1.4.3 grid_3.6.1 cli_1.1.0
[36] tools_3.6.1 magrittr_1.5 lazyeval_0.2.2 crayon_1.3.4 ape_5.3
[41] pkgconfig_2.0.3 zeallot_0.1.0 xml2_1.2.2 lubridate_1.7.4 assertthat_0.2.1
[46] httr_1.4.1 rstudioapi_0.10 R6_2.4.0 nlme_3.1-141 compiler_3.6.1
LS0tCnRpdGxlOiAiUGh5bG9nZW5ldGljIFRyZWUiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIGNzczogc3R5bGUuY3NzCiAgICB0aGVtZTogcGFwZXIKLS0tCgpMb2FkIHBhY2thZ2VzCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShnZ3JpZGdlcykKbGlicmFyeShnZ3N0YW5jZSkKbGlicmFyeSh0cmVlaW8pCmxpYnJhcnkoZ2d0cmVlKQpsaWJyYXJ5KHRpZHl0cmVlKQpgYGAKCkxvYWQgYW5kIGNvbWJpbmUgZGF0YQoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CnN0dWRpZXMgPC0gcmVhZF9jc3YoIi4uL2RhdGEvc3R1ZGllc19nc2hlZXQuY3N2IikKc3BlY2llcyA8LSByZWFkX2NzdigiLi4vZGF0YS9zcGVjaWVzX2dzaGVldC5jc3YiKQpmdWxsdHJlZSA8LSByZWFkLm5leHVzKCIuLi9kYXRhL2NvbnNlbnN1c1RyZWVfMTBrVHJlZXNfMjk4UHJpbWF0ZXNfVjMubmV4IikKcmVmcyA8LSByZWFkX2NzdigiLi4vZGF0YS9yZWZfbm9kZXMuY3N2IikKYGBgCgpgYGB7cn0KZGF0YSA8LSBzdHVkaWVzICU+JSAKICBsZWZ0X2pvaW4oc3BlY2llcywgYnkgPSBjKCJzcGVjaWVzIiA9ICJzcGVjaWVzX2ZpbGUiKSkgJT4lIAogIHJlbmFtZShsYWJlbCA9IHNwZWNpZXNfdHJlZSwgbGFiZWwyID0gdXBkYXRlZF9ub21lbmNsYXR1cmUsIG51bSA9IG4pICU+JSAKICBtdXRhdGUobGFiZWwyID0gaWZlbHNlKGlzLm5hKGxhYmVsMiksIGxhYmVsLCBsYWJlbDIpKSAlPiUgCiAgc2VsZWN0KGxhYmVsLCBsYWJlbDIsIHN0dWR5SUQsIHNwZWNpZXMsIHNpdGUsIG51bSkKYGBgCgpgYGB7cn0KZGF0YTIgPC0gZGF0YSAlPiUKICBncm91cF9ieShsYWJlbCwgbGFiZWwyLCBzcGVjaWVzKSAlPiUgCiAgc3VtbWFyaXNlKE5zaXRlcyA9IG5fZGlzdGluY3Qoc2l0ZSksIE5zdHVkaWVzID0gbl9kaXN0aW5jdChzdHVkeUlEKSkgJT4lIAogIG11dGF0ZShkaXZfc2NvcmUgPSBOc2l0ZXMvTnN0dWRpZXMpCmBgYAoKYGBge3J9CiMgdHVybiB0cmVlIGludG8gdGlkeSBkYXRhZnJhbWUKdHJlZTIgPC0gZnVsbHRyZWUgJT4lIAogIGRyb3AudGlwKGMoIlBhbl90cm9nbG9keXRlc19zY2h3ZWluZnVydGhpaSIsICJQYW5fdHJvZ2xvZHl0ZXNfdHJvZ2xvZHl0ZXMiLAogICAgICAgICAgICAgIlBhbl90cm9nbG9keXRlc192ZWxsZXJvc3VzIiwgIlBvbmdvX3B5Z21hZXVzIiwgIkNlcmNvcGl0aGVjdXNfY2VwaHVzX2NlcGh1cyIsCiAgICAgICAgICAgICAiQ2VyY29waXRoZWN1c19lcnl0aHJvZ2FzdGVyX2VyeXRocm9nYXN0ZXIiLCAiRXVsZW11cl9mdWx2dXNfbWF5b3R0ZW5zaXMiLAogICAgICAgICAgICAgIkhhcGFsZW11cl9ncmlzZXVzX2dyaXNldXMiLCAiTWljcm9jZWJ1c19sb2tvYmVuc2lzIiwgIkxlcGlsZW11cl9taXRzaW5qb2Vuc2lzIikpICU+JQogIGFzX3RpYmJsZQoKaW5uZXJfbm9kZXMgPC0gYygyODk6Mjk4LCAzMDc6MzA4LCAzMTM6MzE5LCAzMjE6MzI1LCAzMjcsIDMyOTozNDYsIDM0OTozNTEsIDM1NTozNTcsIDM1OSwgMzc1OjM4MywgMzg4LCAzOTI6Mzk1LCAzOTc6NDAzLCA0MDU6NDE2LCA0MjM6NDI2LCA0Mjg6NDMyLCA0Mzg6NDQyLCA0NDY6NDQ4LCA0NTA6NDU0LCA0NTc6NDY0LCA0NjY6NDcxLCA0NzM6NDc3LCA0ODE6NDkyLCA1MDQsIDUyMjo1MjMsIDUyNzo1MjksIDUzMjo1MzYsIDU0Mjo1NDQsIDU1MDo1NTIsIDU1NSwgNTU3KQoKdHJlZTMgPC0gdHJlZTIgJT4lIAogIG11dGF0ZShsYWJlbCA9IGZjdF9yZWNvZGUobGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBvbmdvX3NwcCIgPSAiUG9uZ29fYWJlbGlpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQYW5fdHJvZ2xvZHl0ZXMiID0gIlBhbl90cm9nbG9keXRlc192ZXJ1cyIpKSAlPiUgCiAgbGVmdF9qb2luKGRhdGEyKSAlPiUgCiAgbGVmdF9qb2luKHNwZWNpZXMsIGJ5ID0gYygibGFiZWwiID0gInNwZWNpZXNfdHJlZSIpKSAlPiUgCiAgc2VsZWN0KC1sYWJlbCwgLWxhYmVsMiwgLXNwZWNpZXNfZmlsZSkgJT4lCiAgcmVuYW1lKGxhYmVsID0gdXBkYXRlZF9ub21lbmNsYXR1cmUpICU+JQogIG11dGF0ZSgKICAgIGhhc04gPSBpZmVsc2UoaXMubmEoTnN0dWRpZXMpLCAuMSwgLjUpLCAjIHVzZWQgdG8gc2l6ZSBicmFuY2hlcyArIGNvbG9yIHRoZSB0aXAgbGFiZWxzCiAgICBoYXNOMiA9IGlmZWxzZShpcy5uYShOc3R1ZGllcykgJiAhKG5vZGUgJWluJSBpbm5lcl9ub2RlcyksIDAsIC41KSwgIyB1c2VkIHRvIGNvbG9yIGJyYW5jaGVzCiAgICBsYWJlbCA9IHN0cl9yZXBsYWNlX2FsbChsYWJlbCwgIl8iLCAiICIpLAogICAgbGFiZWwgPSBpZmVsc2UoaXMubmEobGFiZWwpICYgc3BlY2llcyA9PSAib3Jhbmd1dGFuIiwgIlBvbmdvIHNwcCIsIAogICAgICAgICAgICAgICAgICAgaWZlbHNlKGlzLm5hKGxhYmVsKSAmIHNwZWNpZXMgPT0gImNoaW1wYW56ZWUiLCAiUGFuIHRyb2dsb2R5dGVzIiwgbGFiZWwpKSkgJT4lIAogIGxlZnRfam9pbihyZWZzKSAlPiUgCiAgZ3JvdXBDbGFkZShyZWZzJG5vZGVbLTFdKSAlPiUgCiAgbXV0YXRlKGdyb3VwID0gZmN0X3JlY29kZShncm91cCwgIjIiID0gIjEiKSkKCiMgdHVybiBiYWNrIGludG8gdHJlZQp0cmVlNCA8LSBhcy50cmVlZGF0YSh0cmVlMykKYGBgCgojIENpcmN1bGFyIHRyZWUgb2YgdGhlIDEwa3RyZWUgcHJpbWF0ZXMKCmBgYHtyfQpjb2xzIDwtIHZpcmlkaXMoNCwgZW5kID0gLjkpCmBgYAoKYGBge3J9CnAgPC0gZ2d0cmVlKHRyZWU0LCBhZXMoYWxwaGEgPSBoYXNOMiksIGxheW91dCA9ICJjaXJjdWxhciIpICsgIyBzaXplID0gaGFzTiwgCiAgIyBoaWdobGlnaHQgY2xhZGVzIHdpdGggYmFja2dyb3VuZCBjb2xvcnMKICBnZW9tX2hpbGlnaHQobm9kZSA9IDQ3OCwgZmlsbCA9IGNvbHNbMV0sIGFscGhhID0gLjMpICsKICBnZW9tX2hpbGlnaHQobm9kZSA9IDQ4MSwgZmlsbCA9IGNvbHNbMV0sIGFscGhhID0gLjMpICsKICBnZW9tX2hpbGlnaHQobm9kZSA9IDQxNCwgZmlsbCA9IGNvbHNbMl0sIGFscGhhID0gLjMpICsKICBnZW9tX2hpbGlnaHQobm9kZSA9IDI5MywgZmlsbCA9IGNvbHNbM10sIGFscGhhID0gLjMpICsKICBnZW9tX2hpbGlnaHQobm9kZSA9IDM5NywgZmlsbCA9IGNvbHNbNF0sIGFscGhhID0gLjMpICsKICAjIHBsb3QgdHJlZSBhZ2FpbiB0byBiZSBvbiB0b3Agb2YgdGhlIGhpZ2hsaWdodHMKICBnZW9tX3RyZWUoKSArCiAgIyByb290CiAgZ2VvbV9yb290cG9pbnQoc2l6ZSA9IDEpICsKICAjIHRpcHMKICBnZW9tX3RpcHBvaW50KGFlcyhzaXplID0gTnN0dWRpZXMpLCBhbHBoYSA9IC43KSArCiAgZ2VvbV90aXBsYWIyKGFlcyhhbHBoYSA9IGhhc04pLCBvZmZzZXQgPSAzLCBzaXplID0gMykgKwogICMgdHdlYWsgc2NhbGVzCiAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZSA9IGMoLjIsIDEpKSArCiAgc2NhbGVfc2l6ZV9hcmVhKG1heF9zaXplID0gMTUpICsKICAjIHdpZGVuIHBsb3R0aW5nIGFyZWEKICB4bGltKE5BLCAxMDApCgpwIDwtIHJvdGF0ZShwLCAyOTIpCmBgYAoKYGBge3J9CnBjb2wgPC0gZ2dwbG90KHRpYmJsZShjb2xzID0gY29scywgeCA9IDE6NCksIGFlcyh4LCB5ID0gMSwgY29sID0gY29scykpICsKICBnZW9tX3BvaW50KHNpemUgPSA2LCBhbHBoYSA9IC4zKSArCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoIkNsYWRlIiwgZ3VpZGUgPSAibGVnZW5kIiwgYnJlYWtzID0gY29sc1s0OjFdLCAKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJIb21pbm9pZGVhIiwgIkNlcmNvcGl0aGVjb2lkZWEiLCAiUGxhdHlycmhpbmkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUYXJzaWlmb3JtZXMgJiBTdHJlcHNpcnJoaW5pIikpICsKICB0aGVtZV9jb3dwbG90KCkKCmwxIDwtIGdldF9sZWdlbmQocGNvbCkKYGBgCgpgYGB7cn0KcHNpemUgPC0gZ2dwbG90KGRhdGEyLCBhZXMoc2l6ZSA9IE5zdHVkaWVzLCB4ID0gMSwgeSA9IDEpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IC43KSArCiAgc2NhbGVfc2l6ZV9hcmVhKCJOdW1iZXIgb2YgU3R1ZGllcyIsIG1heF9zaXplID0gMTUpICsKICB0aGVtZV9jb3dwbG90KCkKCmwyIDwtIGdldF9sZWdlbmQocHNpemUpCmBgYAoKYGBge3IsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUuNSwgY2FjaGU9VFJVRX0KcHggPC0gcGxvdF9ncmlkKHAsIHBsb3RfZ3JpZChOQSwgbDEsIGwyLCBOQSwgbmNvbCA9IDEsIHJlbF9oZWlnaHRzID0gYyguMywgLjE1LCAuMTUsIC4zKSksIE5BLAogICAgICAgICAgbnJvdyA9IDEsIHJlbF93aWR0aHMgPSBjKDEsIC4yLCAuMSkpCgpweApgYGAKCmBgYHtyLCBjYWNoZT1UUlVFfQpnZ3NhdmUoIi4uL2dyYXBocy9waHlsb19mdWxsLnBkZiIsIHB4LCB3aWR0aCA9IDcsIGhlaWdodCA9IDUuNSwgc2NhbGUgPSAyKQpnZ3NhdmUoIi4uL2dyYXBocy9waHlsb19mdWxsLnBuZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNS41LCBzY2FsZSA9IDIpCmdnc2F2ZSgiLi4vZ3JhcGhzL3BoeWxvX2Z1bGwudGlmZiIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNS41LCBzY2FsZSA9IDIsIHR5cGUgPSAiY2Fpcm8iLCAKICAgICAgIGNvbXByZXNzaW9uID0gImx6dyIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTgsIGNhY2hlPVRSVUUsIGV2YWw9RkFMU0V9CiMgdG8gZmlndXJlIG91dCBub2RlIG51bWJlcnMKbjEgPC0gcCArIGdlb21fdGV4dChhZXMobGFiZWwgPSBub2RlLCB4ID0gYnJhbmNoKSwgc2l6ZSA9IDIsIGNvbCA9ICJibHVlIiwgdmp1c3QgPSAtLjUpCmdnc2F2ZSgiLi4vZ3JhcGhzL2Z1bGxfdHJlZV9ub2Rlc19jaXJjdWxhci5wZGYiLCBuMSwgd2lkdGggPSA4LCBoZWlnaHQgPSA4LCBzY2FsZSA9IDIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTIwLCBjYWNoZT1UUlVFLCBldmFsPUZBTFNFfQpuMiA8LSBnZ3RyZWUodHJlZTQsIGFlcyhzaXplID0gaGFzTiwgYWxwaGEgPSBoYXNOMikpICsKICAjIGhpZ2hsaWdodCBjbGFkZXMgd2l0aCBiYWNrZ3JvdW5kIGNvbG9ycwogIGdlb21faGlsaWdodChub2RlID0gNDc4LCBmaWxsID0gY29sc1sxXSwgYWxwaGEgPSAuMykgKwogIGdlb21faGlsaWdodChub2RlID0gNDgxLCBmaWxsID0gY29sc1sxXSwgYWxwaGEgPSAuMykgKwogIGdlb21faGlsaWdodChub2RlID0gNDE0LCBmaWxsID0gY29sc1syXSwgYWxwaGEgPSAuMykgKwogIGdlb21faGlsaWdodChub2RlID0gMjkzLCBmaWxsID0gY29sc1szXSwgYWxwaGEgPSAuMykgKwogIGdlb21faGlsaWdodChub2RlID0gMzk3LCBmaWxsID0gY29sc1s0XSwgYWxwaGEgPSAuMykgKwogICMgcGxvdCB0cmVlIGFnYWluIHRvIGJlIG9uIHRvcCBvZiB0aGUgaGlnaGxpZ2h0cwogIGdlb21fdHJlZSgpICsKICAjIHJvb3QKICBnZW9tX3Jvb3RlZGdlKHJvb3RlZGdlID0gMikgKwogIGdlb21fcm9vdHBvaW50KHNpemUgPSAxKSArCiAgIyBub2RlIGxhYmVscwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBub2RlLCB4ID0gYnJhbmNoKSwgc2l6ZSA9IDIsIGNvbCA9ICJibHVlIiwgdmp1c3QgPSAtLjUpICsKICAjIHRpcHMKICBnZW9tX3RpcHBvaW50KGFlcyhzaXplID0gTnN0dWRpZXMpLCBhbHBoYSA9IC43KSArCiAgZ2VvbV90aXBsYWIoYWVzKGFscGhhID0gaGFzTiksIG9mZnNldCA9IDEuOCwgc2l6ZSA9IDMpICsKICAjIHR3ZWFrIHNjYWxlcwogIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKC4yLCAxKSkgKwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoLjUsIDE1KSkgKwogICMgd2lkZW4gcGxvdHRpbmcgYXJlYQogIGV4cGFuZF9saW1pdHMoeCA9IDkwKSArCiAgdGhlbWVfdHJlZTIoKQoKZ2dzYXZlKCIuLi9ncmFwaHMvZnVsbF90cmVlX25vZGVzLnBkZiIsIG4yLCB3aWR0aCA9IDgsIGhlaWdodCA9IDIwLCBzY2FsZSA9IDIpCmBgYAoKCiMgU2FtcGxlIHNpemUgaW4gZGV0YWlsCgpgYGB7cn0KIyBzdWJzZXQgdHJlZSB0byBqdXN0IHRob3NlIHNwZWNpZXMgd2hvIGhhdmUgc2FtcGxlIHNpemVzIHJlcG9ydGVkLCBpLmUuIHRob3NlIHdobyB3ZXJlIHRlc3RlZAp0b19kcm9wIDwtIHRyZWUzICU+JSBmaWx0ZXIoaXMubmEoTnN0dWRpZXMpKSAlPiUgcHVsbChsYWJlbCkKdHJlZTUgPC0gZHJvcC50aXAodHJlZTQsIHRvX2Ryb3ApCmQzIDwtIGRhdGEgJT4lIAogIG11dGF0ZShsYWJlbCA9IHN0cl9yZXBsYWNlX2FsbChsYWJlbDIsICJfIiwgIiAiKSkgJT4lIAogIGdyb3VwX2J5KGxhYmVsLCBzcGVjaWVzLCBzdHVkeUlEKSAlPiUgCiAgc3VtbWFyaXNlKG51bSA9IHN1bShudW0pKQpgYGAKCmBgYHtyfQpkMyAlPiUgYXJyYW5nZShkZXNjKG51bSkpCmBgYAoKYGBge3J9CiMgZmlsdGVyIHN1cGVyIGxhcmdlIHNhbXBsZXMgb3V0IGZvciB2aXN1YWxpemF0aW9uPyBub3RlIGluIGNhcHRpb24KIyBzcGVjaWVzIHdpdGggbW9yZSB0aGFuIFggc2l0ZXMgY2FuIGdldCBhIGRlbnNpdHkKZDNhIDwtIGQzICU+JSBncm91cF9ieShzcGVjaWVzKSAlPiUgZmlsdGVyKG5fZGlzdGluY3Qoc3R1ZHlJRCkgPj0gNCwgbnVtIDw9IDIwMCkKZDNiIDwtIGQzICU+JSAjIHNldGRpZmYoZDMsIGQzYSkgJT4lICMjIDwtIHRvIE5PVCBzaG93IHBvaW50cyBmb3IgZGVuc2l0aWVzCiAgZ3JvdXBfYnkoc3BlY2llcykgJT4lIAogICMgY3JlYXRlIHZhcmlhYmxlIG51bTIgaXMgTkEgaWYgdGhlcmUncyBvbmx5IG9uZSBkYXRhIHBvaW50IGZvciBhIHNwZWNpZXMKICAjIC0tPiB0aG9zZSBzcGVjaWVzIHdpbGwgb25seSBnZXQgdGhlIHZlcnRpY2FsIGNyb3NzYmFyCiAgbXV0YXRlKGZsYWcgPSBuX2Rpc3RpbmN0KHN0dWR5SUQpID09IDEpICU+JSAKICB1bmdyb3VwICU+JSAKICBtdXRhdGUobnVtMiA9IGlmZWxzZShmbGFnLCBOQSwgbnVtKSkgJT4lIAogIGZpbHRlcihudW0gPD0gMjAwKQoKIyBmb3IgdmVydGljYWwgY3Jvc3NiYXIgPSBtZWRpYW4KZDQgPC0gZDMgJT4lIAogIGdyb3VwX2J5KGxhYmVsLCBzcGVjaWVzKSAlPiUgCiAgc3VtbWFyaXNlKE1kbiA9IG1lZGlhbihudW0sIG5hLnJtID0gVCkpICMgdG90YWxOID0gc3VtKG51bSksIHNpdGVzTiA9IG5fZGlzdGluY3Qoc2l0ZSkKCiMgZm9yIHZlcnRpY2FsIGxpbmUgaW4gcmlkZ2UgcGxvdCAoZ3JhbmQgbWVkaWFuKQojICsgaGFja3kgd2F5IHRvIG1ha2UgaG9yaXpvbnRhbCBncmlkIGxpbmVzIGZvciByaWdodCBwYW5lbCBvbmx5CnYgPC0gdGliYmxlKHJlZmVyZW5jZSA9IGMoTkEsIG1lZGlhbihkMyRudW0sIG5hLnJtID0gVCkpLCAucGFuZWwgPSBjKCJUcmVlIiwgInhTYW1wbGUgc2l6ZSIpKQpoIDwtIHRpYmJsZShyZWZlcmVuY2UgPSBjKE5BLCAxOk50aXAodHJlZTUpKSwgLnBhbmVsID0gYygiVHJlZSIsIHJlcCgieFNhbXBsZSBzaXplIiwgTnRpcCh0cmVlNSkpKSkKCiMgZm9yIGF4aXMgbGFiZWxzCmF4IDwtIHRpYmJsZShsYWIgPSBjKCJEaXN0YW5jZSAoTWlsbGlvbnMgb2YgeWVhcnMpIiwgIlNhbXBsZSBzaXplIiksIAogICAgICAgICAgICAgeCA9IGMoNjAsIDEwMCksIHkgPSAtNCwgLnBhbmVsID0gYygiVHJlZSIsICJ4U2FtcGxlIHNpemUiKSkKCiMgTnNpdGVzL3N0dWRpZXMgbGFiZWxzCk5sYWIgPC0gdGliYmxlKGxhYiA9IGMoIiMgU2l0ZXMiLCAiIyBTdHVkaWVzIiksIHggPSBjKDEyNSwgMTM2KSwgeSA9IE50aXAodHJlZTUpICsgMSwgCiAgICAgICAgICAgICAucGFuZWwgPSAiVHJlZSIpCmBgYAoKYGBge3IsIGNhY2hlPVRSVUV9CiMgTEVGVCBGQUNFVApxIDwtIGdndHJlZSh0cmVlNSwgYWVzKGNvbCA9IGdyb3VwKSkgKwogICMgcm9vdAogIGdlb21fcm9vdGVkZ2Uocm9vdGVkZ2UgPSA1KSArCiAgIyB0aXAgbGFiZWxzCiAgZ2VvbV90aXBwb2ludChhZXMoc2l6ZSA9IE5zdHVkaWVzKSwgc2hhcGUgPSAyMSwgZmlsbCA9ICJ3aGl0ZSIpICsKICBnZW9tX3RpcHBvaW50KGFlcyhzaXplID0gTnNpdGVzKSwgc3Ryb2tlID0gMCwgYWxwaGEgPSAuOCkgKwogICMgZ2VvbV90aXBsYWIoYWVzKGxhYmVsID0gc3RyX2MobGFiZWwsICIgKCIsIE5zaXRlcywgIi8iLCBOc3R1ZGllcywgIikiKSksIG9mZnNldCA9IDQsIHNpemUgPSAzKSArCiAgZ2VvbV90aXBsYWIob2Zmc2V0ID0gNCwgc2l6ZSA9IDMpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gTnNpdGVzKSwgeCA9IDEzNSwgaGp1c3QgPSAxLCBzaXplID0gMykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBOc3R1ZGllcyksIHggPSAxNDIsIGhqdXN0ID0gMSwgc2l6ZSA9IDMpICsKICAjIHR3ZWFrIHNjYWxlcwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5MzAiLCBjb2xzKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbHMpICsKICBzY2FsZV9zaXplX2FyZWEobWF4X3NpemUgPSA4KSArCiAgIyBkaXNwbGF5IHRpbWVzY2FsZSBhdCB0aGUgYm90dG9tCiAgdGhlbWVfdHJlZTIoKSArCiAgeGxpbV90cmVlKDE0MikgKwogIHhsaW1fZXhwYW5kKGMoMCwgMTc1KSwgInhTYW1wbGUgc2l6ZSIpICsKICAjIGFkZCBheGlzICsgTnN0dWRpZXMvc2l0ZXMgbGFiZWxzCiAgZ2VvbV90ZXh0KGRhdGEgPSBheCwgYWVzKGxhYmVsID0gbGFiKSwgY29sID0gImJsYWNrIikgKwogIGdlb21fdGV4dChkYXRhID0gTmxhYiwgYWVzKGxhYmVsID0gbGFiKSwgY29sID0gImJsYWNrIiwgc2l6ZSA9IDIuNSkgKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBleHBhbmRfc2NhbGUobXVsdCA9IGMoMCwgLjAxKSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygyLCBOdGlwKHRyZWU1KS0xKSwgb29iID0gZnVuY3Rpb24oeCwgLi4uKSB4KSArCiAgY29vcmRfY2FydGVzaWFuKGNsaXAgPSAib2ZmIikgKwogICMgYWRkIHJlZmVyZW5jZSBsaW5lcyAodGhlc2Ugd2lsbCBzaG93IHVwIG9uIHJpZ2h0IHBhbmVsIG9mIGZhY2V0X3Bsb3Qgb25seSkKICBnZW9tX2hsaW5lKGRhdGEgPSBoLCBhZXMoeWludGVyY2VwdCA9IHJlZmVyZW5jZSksIGx3ZCA9IC4yLCBjb2wgPSAiZ3JleSIsIGFscGhhID0gLjUpICsKICBnZW9tX3ZsaW5lKGRhdGEgPSB2LCBhZXMoeGludGVyY2VwdCA9IHJlZmVyZW5jZSksIGx3ZCA9IDEuNSwgY29sID0gImdyZXkiLCBhbHBoYSA9IC4zKSArCiAgIyByZW1vdmUgZmFjZXQgc3RyaXBzLCBleHBhbmQgYm90dG9tIG1hcmdpbiAodG8gbWFrZSBzcGFjZSBmb3IgeCBheGlzIGxhYmVscykKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDEsIDEsIDIsIDEuNSksICJjbSIpLCBwYW5lbC5zcGFjaW5nID0gdW5pdCgxLCAiY20iKSkKCnEgPC0gcm90YXRlKHEsIDcyKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD04LCBjYWNoZT1UUlVFfQojIHJpZ2h0LXNpZGUgdml6IGRlcGVuZHMgb24gdGhlIG51bWJlciBvZiBzaXRlcyBwZXIgc3BlY2llczoKIyAxIHNpdGUgPSB2ZXJ0aWNhbCBjcm9zc2JhciBvbmx5CiMgMisgc2l0ZXMgPSBwb2ludHMgKyBjcm9zc2JhciBhdCBtZWRpYW4KIyBYKyBzaXRlcyA9IGRlbnNpdGllcyAoY3VycmVudGx5LCBYID0gNCBqdXN0IHRvIGlsbHVzdHJhdGUpCgojIGRpcnR5IGhhY2s6IHggaW4gZnJvbnQgb2YgIlNhbXBsZSBzaXplIiBpcyB0byBoYXZlIHRoYXQgcGFuZWwgc29ydCB0byB0aGUgcmlnaHQgKGFscGhhYmV0aWNhbGx5KSB1bnRpbCBJIGZpZ3VyZSBvdXQgd2h5IGl0IGRvZXNuJ3QganVzdCBnbyBieSBvcmRlci4gVGhpcyBjcm9wcGVkIHVwIGFzIGFuIGlzc3VlIHdoZW4gSSBhZGRlZCB0aGUgZHVtbXkgcG9pbnQgZm9yIHRoZSB4LWF4aXMgZXhwYW5zaW9uLi4uCgojIEFERCBSSUdIVCBGQUNFVApxeCA8LSBxICU+JSAKICAjIGRlbnNpdGllcyBmb3Igc3BlY2llcyB3aXRoIGVub3VnaCBzaXRlcwogIGZhY2V0X3Bsb3QoInhTYW1wbGUgc2l6ZSIsIGQzYSwgZ2VvbV9kZW5zaXR5X3JpZGdlcywgCiAgICAgICAgICAgICBhZXMoeCA9IG51bSwgZ3JvdXAgPSBsYWJlbCwgZmlsbCA9IGdyb3VwLCBoZWlnaHQgPSAuLmRlbnNpdHkuLiksCiAgICAgICAgICAgICBhbHBoYSA9IC41LCBsd2QgPSAuMywgc2NhbGUgPSAuMykgJT4lCiAgIyB2ZXJ0aWNhbCBjcm9zc2JhciBmb3IgTWRuCiAgZmFjZXRfcGxvdCgieFNhbXBsZSBzaXplIiwgZDQsIGdlb21fY3Jvc3NiYXJoLCBhZXMoeCA9IE1kbiwgeG1pbiA9IE1kbiwgeG1heCA9IE1kbiwgZ3JvdXAgPSBsYWJlbCwKICAgICAgICAgICAgIGNvbCA9IGdyb3VwKSwgYWxwaGEgPSAuNSwgd2lkdGggPSAuNiwgZmF0dGVuID0gMS41KSAlPiUKICAjIHZlcnRpY2FsIG1hcmsgZm9yIGluZGl2aWR1YWwgc2l0ZXMKICBmYWNldF9wbG90KCJ4U2FtcGxlIHNpemUiLCBkM2IsIGdlb21faml0dGVyLCBhZXMoeCA9IG51bTIsIGdyb3VwID0gbGFiZWwpLCBzaGFwZSA9ICJ8Iiwgc2l6ZSA9IDIuNSwKICAgICAgICAgICAgIHdpZHRoID0gLjUsIGhlaWdodCA9IDAsIGFscGhhID0gLjUpCmBgYAoKYGBge3J9CiMgYWRkIGxlZ2VuZHMKcHNpemUgPC0KICBnZ3Bsb3QoZGF0YTIsIGFlcyh4ID0gMSwgeSA9IDEpKSArCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IE5zdHVkaWVzKSwgY29sID0gTkEpICsKICBnZW9tX3BvaW50KGFlcyhzaXplID0gTnNpdGVzKSwgc3Ryb2tlID0gMCwgYWxwaGEgPSAuOCkgKwogIHNjYWxlX3NpemVfYXJlYSgiTnVtYmVyIG9mIFNpdGVzIiwgbWF4X3NpemUgPSA4LCBicmVha3MgPSBjKDEsIDUsIDEwLCAyNSwgNTApKSArCiAgdGhlbWVfY293cGxvdCgpCgpwc2l6ZTIgPC0KICBnZ3Bsb3QoZGF0YTIsIGFlcyh4ID0gMSwgeSA9IDEpKSArCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IE5zdHVkaWVzKSwgc2hhcGUgPSAyMSwgZmlsbCA9ICJ3aGl0ZSIpICsKICBzY2FsZV9zaXplX2FyZWEoIlxuTnVtYmVyIG9mIFN0dWRpZXMiLCBtYXhfc2l6ZSA9IDgsIGJyZWFrcyA9IGMoMSwgNSwgMTAsIDI1LCA1MCwgMTAwKSkgKwogIHRoZW1lX2Nvd3Bsb3QoKQoKbDIgPC0gZ2V0X2xlZ2VuZChwc2l6ZSkKbDMgPC0gZ2V0X2xlZ2VuZChwc2l6ZTIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTgsIGNhY2hlPVRSVUV9CnF4MiA8LSBwbG90X2dyaWQocXgsIHBsb3RfZ3JpZChOQSwgbDEsIGwyLCBsMywgTkEsIG5jb2wgPSAxLCByZWxfaGVpZ2h0cyA9IGMoLjMsIC4xLCAuMSwgLjEsIC4zKSksIE5BLAogICAgICAgICAgbnJvdyA9IDEsIHJlbF93aWR0aHMgPSBjKDEsIC4yLCAuMSkpCgpxeDIKYGBgCgpgYGB7cn0KZ2dzYXZlKCIuLi9ncmFwaHMvcGh5bG9fcmlkZ2Vfc2l0ZS5wZGYiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDgsIHNjYWxlID0gMikKZ2dzYXZlKCIuLi9ncmFwaHMvcGh5bG9fcmlkZ2Vfc2l0ZS5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDgsIHNjYWxlID0gMikKZ2dzYXZlKCIuLi9ncmFwaHMvcGh5bG9fcmlkZ2Vfc2l0ZS50aWZmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA4LCBzY2FsZSA9IDIsIHR5cGUgPSAiY2Fpcm8iLCAKICAgICAgIGNvbXByZXNzaW9uID0gImx6dyIpCmBgYAoKIyBEaXZlcnNpdHkgc2NvcmUKCmBgYHtyLCBldmFsPUZBTFNFfQojIHN1YnNldCB0cmVlIHRvIGp1c3QgdGhvc2Ugc3BlY2llcyB3aG8gaGF2ZSBzYW1wbGUgc2l6ZXMgcmVwb3J0ZWQsIGkuZS4gdGhvc2Ugd2hvIHdlcmUgdGVzdGVkCnRvX2Ryb3AgPC0gdHJlZTMgJT4lIGZpbHRlcihpcy5uYShOc3R1ZGllcykgfCBOc3R1ZGllcyA8IDIpICU+JSBwdWxsKGxhYmVsKQp0cmVlNiA8LSBkcm9wLnRpcCh0cmVlNCwgdG9fZHJvcCkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9NSwgY2FjaGU9VFJVRSwgZXZhbD1GQUxTRX0KZ2d0cmVlKHRyZWU2LCBhZXMoY29sID0gZ3JvdXApKSArCiAgIyByb290CiAgZ2VvbV9yb290ZWRnZShyb290ZWRnZSA9IDUpICsKICAjIHRpcCBsYWJlbHMKICBnZW9tX3RpcHBvaW50KGFlcyhzaXplID0gTnN0dWRpZXMpLCBzaGFwZSA9IDIxLCBmaWxsID0gIndoaXRlIikgKwogIGdlb21fdGlwcG9pbnQoYWVzKHNpemUgPSBOc2l0ZXMpLCBzdHJva2UgPSAwLCBhbHBoYSA9IC44KSArCiAgZ2VvbV90aXBsYWIob2Zmc2V0ID0gNCwgc2l6ZSA9IDMpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gTnNpdGVzKSwgeCA9IDExMywgaGp1c3QgPSAxLCBzaXplID0gMykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBOc3R1ZGllcyksIHggPSAxMjAsIGhqdXN0ID0gMSwgc2l6ZSA9IDMpICsKICAjIHR3ZWFrIHNjYWxlcwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5MzAiLCBjb2xzKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbHMpICsKICBzY2FsZV9zaXplX2FyZWEobWF4X3NpemUgPSA4KSArCiAgIyBkaXNwbGF5IHRpbWVzY2FsZSBhdCB0aGUgYm90dG9tCiAgdGhlbWVfdHJlZTIoKSArCiAgeGxpbV90cmVlKDEyMCkgKwogIHhsYWIoIkRpc3RhbmNlIChNaWxsaW9ucyBvZiB5ZWFycykiKQpgYGAKCmBgYHtyfQojIGdnc2F2ZSgiLi4vZ3JhcGhzL3BoeWxvX2Rpdl9zY29yZS5wZGYiLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQuNSwgc2NhbGUgPSAyKQpgYGAKCiMgU2Vzc2lvbiBpbmZvCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKCg==